//===--- PILInstruction.cpp - Instructions for PIL code -------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file defines the high-level PILInstruction classes used for PIL code.
//
//===----------------------------------------------------------------------===//

#include "polarphp/pil/lang/PILInstruction.h"
#include "polarphp/basic/Unicode.h"
#include "polarphp/pil/lang/ApplySite.h"
#include "polarphp/pil/lang/PILBuilder.h"
#include "polarphp/pil/lang/PILCloner.h"
#include "polarphp/pil/lang/PILDebugScope.h"
#include "polarphp/pil/lang/PILVisitor.h"
#include "polarphp/pil/lang/PILFunction.h"
#include "polarphp/basic/AssertImplements.h"
#include "polarphp/clangimporter/ClangModule.h"
#include "polarphp/pil/lang/PILModule.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/ErrorHandling.h"

using namespace polar;
using namespace polar::lowering;

//===----------------------------------------------------------------------===//
// Instruction-specific properties on PILValue
//===----------------------------------------------------------------------===//

PILLocation PILInstruction::getLoc() const { return Location.getLocation(); }

const PILDebugScope *PILInstruction::getDebugScope() const {
   return Location.getScope();
}

void PILInstruction::setDebugScope(const PILDebugScope *DS) {
   if (getDebugScope() && getDebugScope()->InlinedCallSite)
      assert(DS->InlinedCallSite && "throwing away inlined scope info");

   assert(DS->getParentFunction() == getFunction() &&
          "scope belongs to different function");

   Location = PILDebugLocation(getLoc(), DS);
}

//===----------------------------------------------------------------------===//
// ilist_traits<PILInstruction> Implementation
//===----------------------------------------------------------------------===//

// The trait object is embedded into a basic block.  Use dirty hacks to
// reconstruct the BB from the 'self' pointer of the trait.
PILBasicBlock *llvm::ilist_traits<PILInstruction>::getContainingBlock() {
   size_t Offset(
      size_t(&((PILBasicBlock *)nullptr->*PILBasicBlock::getSublistAccess())));
   iplist<PILInstruction> *Anchor(static_cast<iplist<PILInstruction> *>(this));
   return reinterpret_cast<PILBasicBlock *>(reinterpret_cast<char *>(Anchor) -
                                            Offset);
}


void llvm::ilist_traits<PILInstruction>::addNodeToList(PILInstruction *I) {
   assert(I->ParentBB == nullptr && "Already in a list!");
   I->ParentBB = getContainingBlock();
}

void llvm::ilist_traits<PILInstruction>::removeNodeFromList(PILInstruction *I) {
   // When an instruction is removed from a BB, clear the parent pointer.
   assert(I->ParentBB && "Not in a list!");
   I->ParentBB = nullptr;
}

void llvm::ilist_traits<PILInstruction>::
transferNodesFromList(llvm::ilist_traits<PILInstruction> &L2,
                      instr_iterator first, instr_iterator last) {
   // If transferring instructions within the same basic block, no reason to
   // update their parent pointers.
   PILBasicBlock *ThisParent = getContainingBlock();
   if (ThisParent == L2.getContainingBlock()) return;

   // Update the parent fields in the instructions.
   for (; first != last; ++first) {
      POLAR_FUNC_STAT_NAMED("sil");
      first->ParentBB = ThisParent;
   }
}

//===----------------------------------------------------------------------===//
// PILInstruction Implementation
//===----------------------------------------------------------------------===//

// Assert that all subclasses of ValueBase implement classof.
#define NODE(CLASS, PARENT) \
  ASSERT_IMPLEMENTS_STATIC(CLASS, PARENT, classof, bool(const PILNode*));
#include "polarphp/pil/lang/PILNodesDef.h"

PILFunction *PILInstruction::getFunction() {
   return getParent()->getParent();
}
const PILFunction *PILInstruction::getFunction() const {
   return getParent()->getParent();
}

PILModule &PILInstruction::getModule() const {
   return getFunction()->getModule();
}

/// eraseFromParent - This method unlinks 'self' from the containing basic
/// block and deletes it.
///
void PILInstruction::eraseFromParent() {
#ifndef NDEBUG
   for (auto result : getResults()) {
      assert(result->use_empty() && "Uses of PILInstruction remain at deletion.");
   }
#endif
   getParent()->erase(this);
}

void PILInstruction::moveFront(PILBasicBlock *Block) {
   getParent()->remove(this);
   Block->push_front(this);
}

/// Unlink this instruction from its current basic block and insert it into
/// the basic block that Later lives in, right before Later.
void PILInstruction::moveBefore(PILInstruction *Later) {
   if (this == Later)
      return;

   getParent()->remove(this);
   Later->getParent()->insert(Later, this);
}

/// Unlink this instruction from its current basic block and insert it into
/// the basic block that Earlier lives in, right after Earlier.
void PILInstruction::moveAfter(PILInstruction *Earlier) {
   // Since MovePos is an instruction, we know that there is always a valid
   // iterator after it.
   auto Later = std::next(PILBasicBlock::iterator(Earlier));
   moveBefore(&*Later);
}

void PILInstruction::dropAllReferences() {
   MutableArrayRef<Operand> PossiblyDeadOps = getAllOperands();
   for (auto OpI = PossiblyDeadOps.begin(),
           OpE = PossiblyDeadOps.end(); OpI != OpE; ++OpI) {
      OpI->drop();
   }

   // If we have a function ref inst, we need to especially drop its function
   // argument so that it gets a proper ref decrement.
   if (auto *FRI = dyn_cast<FunctionRefBaseInst>(this)) {
      if (!FRI->getInitiallyReferencedFunction())
         return;
      FRI->dropReferencedFunction();
      return;
   }

   // If we have a KeyPathInst, drop its pattern reference so that we can
   // decrement refcounts on referenced functions.
   if (auto *KPI = dyn_cast<KeyPathInst>(this)) {
      if (!KPI->hasPattern())
         return;

      KPI->dropReferencedPattern();
      return;
   }
}

namespace {

class AllResultsAccessor
   : public PILInstructionVisitor<AllResultsAccessor,
      PILInstructionResultArray> {
public:
// Make sure we hit a linker error if we ever miss an instruction.
#define INST(ID, NAME) PILInstructionResultArray visit##ID(ID *I);
#define NON_VALUE_INST(ID, NAME, PARENT, MEMBEHAVIOR, MAYRELEASE)              \
  PILInstructionResultArray visit##ID(ID *I) {                                 \
    return PILInstructionResultArray();                                        \
  }
#define SINGLE_VALUE_INST(ID, TEXTUALNAME, PARENT, MEMBEHAVIOR, MAYRELEASE)    \
  PILInstructionResultArray visit##ID(ID *I) {                                 \
    return PILInstructionResultArray(                                          \
        static_cast<SingleValueInstruction *>(I));                             \
  }
#define MULTIPLE_VALUE_INST(ID, TEXTUALNAME, PARENT, MEMBEHAVIOR, MAYRELEASE)  \
  PILInstructionResultArray visit##ID(ID *I) {                                 \
    return PILInstructionResultArray(I->getAllResults());                      \
  }
#include "polarphp/pil/lang/PILNodesDef.h"
};

} // end anonymous namespace

PILInstructionResultArray PILInstruction::getResultsImpl() const {
   return AllResultsAccessor().visit(const_cast<PILInstruction *>(this));
}

// Initialize the static members of PILInstruction.
int PILInstruction::NumCreatedInstructions = 0;
int PILInstruction::NumDeletedInstructions = 0;

/// Map a PILInstruction name to its PILInstructionKind.
PILInstructionKind polar::getPILInstructionKind(StringRef name) {
#define FULL_INST(ID, NAME, PARENT, MEMBEHAVIOR, MAYRELEASE)  \
  if (name == #NAME)                                          \
    return PILInstructionKind::ID;
#include "polarphp/pil/lang/PILNodesDef.h"

#ifdef NDEBUG
      llvm::errs() << "Unknown PIL instruction name\n";
  abort();
#endif
   llvm_unreachable("Unknown PIL insruction name");
}

/// Map PILInstructionKind to a corresponding PILInstruction name.
StringRef polar::getPILInstructionName(PILInstructionKind kind) {
   switch (kind) {
#define FULL_INST(ID, NAME, PARENT, MEMBEHAVIOR, MAYRELEASE)  \
  case PILInstructionKind::ID:                                \
    return #NAME;
#include "polarphp/pil/lang/PILNodesDef.h"
   }
   llvm_unreachable("bad kind");
}

void PILInstruction::replaceAllUsesOfAllResultsWithUndef() {
   for (auto result : getResults()) {
      result->replaceAllUsesWithUndef();
   }
}

void PILInstruction::replaceAllUsesPairwiseWith(PILInstruction *other) {
   auto results = getResults();

   // If we don't have any results, fast-path out without asking the other
   // instruction for its results.
   if (results.empty()) {
      assert(other->getResults().empty());
      return;
   }

   // Replace values with the corresponding values of the other instruction.
   auto otherResults = other->getResults();
   assert(results.size() == otherResults.size());
   for (auto i : indices(results)) {
      results[i]->replaceAllUsesWith(otherResults[i]);
   }
}

void PILInstruction::replaceAllUsesPairwiseWith(
   const llvm::SmallVectorImpl<PILValue> &NewValues) {
   auto Results = getResults();

   // If we don't have any results, fast-path out without asking the other
   // instruction for its results.
   if (Results.empty()) {
      assert(NewValues.empty());
      return;
   }

   // Replace values with the corresponding values of the list. Make sure they
   // are all the same type.
   assert(Results.size() == NewValues.size());
   for (unsigned i : indices(Results)) {
      assert(Results[i]->getType() == NewValues[i]->getType() &&
             "Can only replace results with new values of the same type");
      Results[i]->replaceAllUsesWith(NewValues[i]);
   }
}

Operand *BeginBorrowInst::getSingleNonEndingUse() const {
   Operand *singleUse = nullptr;
   for (auto *use : getUses()) {
      if (isa<EndBorrowInst>(use->getUser()))
         continue;

      if (singleUse)
         return nullptr;

      singleUse = use;
   }
   return singleUse;
}

namespace {
class InstructionDestroyer
   : public PILInstructionVisitor<InstructionDestroyer> {
public:
#define INST(CLASS, PARENT) \
  void visit##CLASS(CLASS *I) { I->~CLASS(); }
#include "polarphp/pil/lang/PILNodesDef.h"
};
} // end anonymous namespace

void PILInstruction::destroy(PILInstruction *I) {
   InstructionDestroyer().visit(I);
}

namespace {
/// Given a pair of instructions that are already known to have the same kind,
/// type, and operands check any special state in the two instructions that
/// could disrupt equality.
class InstructionIdentityComparer :
   public PILInstructionVisitor<InstructionIdentityComparer, bool> {
public:

   InstructionIdentityComparer(const PILInstruction *L) : LHS(L) { }

   /// Make sure we only process instructions we know how to process.
   bool visitPILInstruction(const PILInstruction *RHS) {
      return false;
   }

   bool visitInjectEnumAddrInst(const InjectEnumAddrInst *RHS) {
      auto *X = cast<InjectEnumAddrInst>(LHS);
      return X->getElement() == RHS->getElement();
   }

   bool visitDestroyAddrInst(const DestroyAddrInst *RHS) {
      return true;
   }

   bool visitReleaseValueInst(const ReleaseValueInst *RHS) {
      return true;
   }

   bool visitReleaseValueAddrInst(const ReleaseValueAddrInst *RHS) {
      return true;
   }

   bool visitRetainValueInst(const RetainValueInst *RHS) {
      return true;
   }

   bool visitRetainValueAddrInst(const RetainValueAddrInst *RHS) {
      return true;
   }

   bool visitDeallocStackInst(const DeallocStackInst *RHS) {
      return true;
   }

   bool visitAllocStackInst(const AllocStackInst *RHS) {
      return true;
   }

   bool visitDeallocBoxInst(const DeallocBoxInst *RHS) {
      return true;
   }

   bool visitAllocBoxInst(const AllocBoxInst *RHS) {
      return true;
   }

   bool visitDeallocRefInst(const DeallocRefInst *RHS) {
      return true;
   }

   bool visitDeallocPartialRefInst(const DeallocPartialRefInst *RHS) {
      return true;
   }

   bool visitAllocRefInst(const AllocRefInst *RHS) {
      auto *LHSInst = cast<AllocRefInst>(LHS);
      auto LHSTypes = LHSInst->getTailAllocatedTypes();
      auto RHSTypes = RHS->getTailAllocatedTypes();
      unsigned NumTypes = LHSTypes.size();
      assert(NumTypes == RHSTypes.size());
      for (unsigned Idx = 0; Idx < NumTypes; ++Idx) {
         if (LHSTypes[Idx] != RHSTypes[Idx])
            return false;
      }
      return true;
   }

   bool visitAllocRefDynamicInst(const AllocRefDynamicInst *RHS) {
      return true;
   }

   bool visitProjectValueBufferInst(const ProjectValueBufferInst *RHS) {
      auto *X = cast<ProjectValueBufferInst>(LHS);
      return X->getValueType() == RHS->getValueType();
   }

   bool visitProjectBoxInst(const ProjectBoxInst *RHS) {
      return true;
   }

   bool visitProjectExistentialBoxInst(const ProjectExistentialBoxInst *RHS) {
      return true;
   }

   bool visitBeginAccessInst(const BeginAccessInst *right) {
      auto left = cast<BeginAccessInst>(LHS);
      return left->getAccessKind() == right->getAccessKind()
             && left->getEnforcement() == right->getEnforcement()
             && left->hasNoNestedConflict() == right->hasNoNestedConflict()
             && left->isFromBuiltin() == right->isFromBuiltin();
   }

   bool visitEndAccessInst(const EndAccessInst *right) {
      auto left = cast<EndAccessInst>(LHS);
      return left->isAborting() == right->isAborting();
   }

   bool visitBeginUnpairedAccessInst(const BeginUnpairedAccessInst *right) {
      auto left = cast<BeginUnpairedAccessInst>(LHS);
      return left->getAccessKind() == right->getAccessKind()
             && left->getEnforcement() == right->getEnforcement()
             && left->hasNoNestedConflict() == right->hasNoNestedConflict()
             && left->isFromBuiltin() == right->isFromBuiltin();
   }

   bool visitEndUnpairedAccessInst(const EndUnpairedAccessInst *right) {
      auto left = cast<EndUnpairedAccessInst>(LHS);
      return left->getEnforcement() == right->getEnforcement()
             && left->isAborting() == right->isAborting()
             && left->isFromBuiltin() == right->isFromBuiltin();
   }

   bool visitStrongReleaseInst(const StrongReleaseInst *RHS) {
      return true;
   }

   bool visitStrongRetainInst(const StrongRetainInst *RHS) {
      return true;
   }

   bool visitLoadInst(const LoadInst *RHS) {
      auto LHSQualifier = cast<LoadInst>(LHS)->getOwnershipQualifier();
      return LHSQualifier == RHS->getOwnershipQualifier();
   }

   bool visitLoadBorrowInst(const LoadBorrowInst *RHS) { return true; }

   bool visitEndBorrowInst(const EndBorrowInst *RHS) { return true; }
   bool visitBeginBorrowInst(const BeginBorrowInst *BBI) { return true; }

   bool visitStoreBorrowInst(const StoreBorrowInst *RHS) {
      auto *X = cast<StoreBorrowInst>(LHS);
      return X->getSrc() == RHS->getSrc() && X->getDest() == RHS->getDest();
   }

   bool visitStoreInst(const StoreInst *RHS) {
      auto *X = cast<StoreInst>(LHS);
      return X->getSrc() == RHS->getSrc() && X->getDest() == RHS->getDest() &&
             X->getOwnershipQualifier() == RHS->getOwnershipQualifier();
   }

   bool visitBindMemoryInst(const BindMemoryInst *RHS) {
      auto *X = cast<BindMemoryInst>(LHS);
      return X->getBoundType() == RHS->getBoundType();
   }

   bool visitFunctionRefInst(const FunctionRefInst *RHS) {
      auto *X = cast<FunctionRefInst>(LHS);
      return X->getInitiallyReferencedFunction() ==
             RHS->getInitiallyReferencedFunction();
   }
   bool visitDynamicFunctionRefInst(const DynamicFunctionRefInst *RHS) {
      auto *X = cast<DynamicFunctionRefInst>(LHS);
      return X->getInitiallyReferencedFunction() ==
             RHS->getInitiallyReferencedFunction();
   }
   bool visitPreviousDynamicFunctionRefInst(
      const PreviousDynamicFunctionRefInst *RHS) {
      auto *X = cast<PreviousDynamicFunctionRefInst>(LHS);
      return X->getInitiallyReferencedFunction() ==
             RHS->getInitiallyReferencedFunction();
   }

   bool visitAllocGlobalInst(const AllocGlobalInst *RHS) {
      auto *X = cast<AllocGlobalInst>(LHS);
      return X->getReferencedGlobal() == RHS->getReferencedGlobal();
   }

   bool visitGlobalAddrInst(const GlobalAddrInst *RHS) {
      auto *X = cast<GlobalAddrInst>(LHS);
      return X->getReferencedGlobal() == RHS->getReferencedGlobal();
   }

   bool visitIntegerLiteralInst(const IntegerLiteralInst *RHS) {
      APInt X = cast<IntegerLiteralInst>(LHS)->getValue();
      APInt Y = RHS->getValue();
      return X.getBitWidth() == Y.getBitWidth() &&
             X == Y;
   }

   bool visitFloatLiteralInst(const FloatLiteralInst *RHS) {
      // Avoid floating point comparison issues by doing a bitwise comparison.
      APInt X = cast<FloatLiteralInst>(LHS)->getBits();
      APInt Y = RHS->getBits();
      return X.getBitWidth() == Y.getBitWidth() &&
             X == Y;
   }

   bool visitStringLiteralInst(const StringLiteralInst *RHS) {
      auto LHS_ = cast<StringLiteralInst>(LHS);
      return LHS_->getEncoding() == RHS->getEncoding()
             && LHS_->getValue().equals(RHS->getValue());
   }

   bool visitStructInst(const StructInst *RHS) {
      // We have already checked the operands. Make sure that the StructDecls
      // match up.
      StructDecl *S1 = cast<StructInst>(LHS)->getStructDecl();
      return S1 == RHS->getStructDecl();
   }

   bool visitStructExtractInst(const StructExtractInst *RHS) {
      // We have already checked that the operands of our struct_extracts
      // match. Thus we need to check the field/struct decl which are not
      // operands.
      auto *X = cast<StructExtractInst>(LHS);
      if (X->getStructDecl() != RHS->getStructDecl())
         return false;
      if (X->getField() != RHS->getField())
         return false;
      return true;
   }

   bool visitRefElementAddrInst(RefElementAddrInst *RHS) {
      auto *X = cast<RefElementAddrInst>(LHS);
      if (X->getField() != RHS->getField())
         return false;
      if (X->getOperand() != RHS->getOperand())
         return false;
      return true;
   }

   bool visitRefTailAddrInst(RefTailAddrInst *RHS) {
      auto *X = cast<RefTailAddrInst>(LHS);
      return X->getTailType() == RHS->getTailType();
   }

   bool visitStructElementAddrInst(const StructElementAddrInst *RHS) {
      // We have already checked that the operands of our struct_element_addrs
      // match. Thus we only need to check the field/struct decl which are not
      // operands.
      auto *X = cast<StructElementAddrInst>(LHS);
      if (X->getStructDecl() != RHS->getStructDecl())
         return false;
      if (X->getField() != RHS->getField())
         return false;
      return true;
   }

   bool visitTupleInst(const TupleInst *RHS) {
      // We have already checked the operands. Make sure that the tuple types
      // match up.
      TupleType *TT1 = cast<TupleInst>(LHS)->getTupleType();
      return TT1 == RHS->getTupleType();
   }

   bool visitTupleExtractInst(const TupleExtractInst *RHS) {
      // We have already checked that the operands match. Thus we only need to
      // check the field no and tuple type which are not represented as operands.
      auto *X = cast<TupleExtractInst>(LHS);
      if (X->getTupleType() != RHS->getTupleType())
         return false;
      if (X->getFieldNo() != RHS->getFieldNo())
         return false;
      return true;
   }

   bool visitTupleElementAddrInst(const TupleElementAddrInst *RHS) {
      // We have already checked that the operands match. Thus we only need to
      // check the field no and tuple type which are not represented as operands.
      auto *X = cast<TupleElementAddrInst>(LHS);
      if (X->getTupleType() != RHS->getTupleType())
         return false;
      if (X->getFieldNo() != RHS->getFieldNo())
         return false;
      return true;
   }

   bool visitMetatypeInst(const MetatypeInst *RHS) {
      // We have already compared the operands/types, so we should have equality
      // at this point.
      return true;
   }

   bool visitValueMetatypeInst(const ValueMetatypeInst *RHS) {
      // We have already compared the operands/types, so we should have equality
      // at this point.
      return true;
   }

   bool visitExistentialMetatypeInst(const ExistentialMetatypeInst *RHS) {
      // We have already compared the operands/types, so we should have equality
      // at this point.
      return true;
   }

   bool visitIndexRawPointerInst(IndexRawPointerInst *RHS) {
      // We have already compared the operands/types, so we should have equality
      // at this point.
      return true;
   }

   bool visitIndexAddrInst(IndexAddrInst *RHS) {
      // We have already compared the operands/types, so we should have equality
      // at this point.
      return true;
   }

   bool visitTailAddrInst(TailAddrInst *RHS) {
      auto *X = cast<TailAddrInst>(LHS);
      return X->getTailType() == RHS->getTailType();
   }

   bool visitCondFailInst(CondFailInst *RHS) {
      // We have already compared the operands/types, so we should have equality
      // at this point.
      return true;
   }

   bool visitApplyInst(ApplyInst *RHS) {
      auto *X = cast<ApplyInst>(LHS);
      return X->getSubstitutionMap() == RHS->getSubstitutionMap();
   }

   bool visitBuiltinInst(BuiltinInst *RHS) {
      auto *X = cast<BuiltinInst>(LHS);
      if (X->getName() != RHS->getName())
         return false;
      return X->getSubstitutions() == RHS->getSubstitutions();
   }

   bool visitEnumInst(EnumInst *RHS) {
      // We already checked operands and types. Only thing we need to check is
      // that the element is the same.
      auto *X = cast<EnumInst>(LHS);
      return X->getElement() == RHS->getElement();
   }

   bool visitUncheckedEnumDataInst(UncheckedEnumDataInst *RHS) {
      // We already checked operands and types. Only thing we need to check is
      // that the element is the same.
      auto *X = cast<UncheckedEnumDataInst>(LHS);
      return X->getElement() == RHS->getElement();
   }

   bool visitSelectEnumInstBase(const SelectEnumInstBase *RHS) {
      // Check that the instructions match cases in the same order.
      auto *X = cast<SelectEnumInstBase>(LHS);

      if (X->getNumCases() != RHS->getNumCases())
         return false;
      if (X->hasDefault() != RHS->hasDefault())
         return false;

      for (unsigned i = 0, e = X->getNumCases(); i < e; ++i) {
         if (X->getCase(i).first != RHS->getCase(i).first)
            return false;
      }

      return true;
   }

   bool visitSelectEnumInst(const SelectEnumInst *RHS) {
      return visitSelectEnumInstBase(RHS);
   }
   bool visitSelectEnumAddrInst(const SelectEnumAddrInst *RHS) {
      return visitSelectEnumInstBase(RHS);
   }

   bool visitSelectValueInst(const SelectValueInst *RHS) {
      // Check that the instructions match cases in the same order.
      auto *X = cast<SelectValueInst>(LHS);

      if (X->getNumCases() != RHS->getNumCases())
         return false;
      if (X->hasDefault() != RHS->hasDefault())
         return false;

      for (unsigned i = 0, e = X->getNumCases(); i < e; ++i) {
         if (X->getCase(i).first != RHS->getCase(i).first)
            return false;
         if (X->getCase(i).second != RHS->getCase(i).second)
            return false;
      }

      return true;
   }

   // Conversion instructions.
   // All of these just return true as they have already had their
   // operands and types checked
   bool visitUncheckedRefCastInst(UncheckedRefCastInst *RHS) {
      return true;
   }

   bool visitUncheckedAddrCastInst(UncheckedAddrCastInst *RHS) {
      return true;
   }

   bool visitUncheckedTrivialBitCastInst(UncheckedTrivialBitCastInst *RHS) {
      return true;
   }

   bool visitUncheckedBitwiseCastInst(UncheckedBitwiseCastInst *RHS) {
      return true;
   }

   bool visitUpcastInst(UpcastInst *RHS) {
      return true;
   }

   bool visitAddressToPointerInst(AddressToPointerInst *RHS) {
      return true;
   }

   bool visitPointerToAddressInst(PointerToAddressInst *RHS) {
      return cast<PointerToAddressInst>(LHS)->isStrict() == RHS->isStrict();
   }

   bool visitRefToRawPointerInst(RefToRawPointerInst *RHS) {
      return true;
   }

   bool visitRawPointerToRefInst(RawPointerToRefInst *RHS) {
      return true;
   }

#define LOADABLE_REF_STORAGE_HELPER(Name)                                      \
  bool visit##Name##ToRefInst(Name##ToRefInst *RHS) { return true; }           \
  bool visitRefTo##Name##Inst(RefTo##Name##Inst *RHS) { return true; }         \
  bool visitStrongCopy##Name##ValueInst(StrongCopy##Name##ValueInst *RHS) {    \
    return true;                                                               \
  }
#define ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \
    LOADABLE_REF_STORAGE_HELPER(Name) \
    bool visitStrongRetain##Name##Inst(const StrongRetain##Name##Inst *RHS) { \
      return true; \
    }
#define UNCHECKED_REF_STORAGE(Name, ...) \
    LOADABLE_REF_STORAGE_HELPER(Name)
#include "polarphp/ast/ReferenceStorageDef.h"
#undef LOADABLE_REF_STORAGE_HELPER

   bool visitThinToThickFunctionInst(ThinToThickFunctionInst *RHS) {
      return true;
   }

   // @todo
//    bool visitThickToObjCMetatypeInst(ThickToObjCMetatypeInst *RHS) {
//      return true;
//    }
//
//    bool visitObjCToThickMetatypeInst(ObjCToThickMetatypeInst *RHS) {
//      return true;
//    }

   bool visitConvertFunctionInst(ConvertFunctionInst *RHS) {
      return true;
   }

   bool visitConvertEscapeToNoEscapeInst(ConvertEscapeToNoEscapeInst *RHS) {
      return true;
   }

   // @todo
//   bool visitObjCMetatypeToObjectInst(ObjCMetatypeToObjectInst *RHS) {
//      return true;
//   }
//
//   bool visitObjCExistentialMetatypeToObjectInst(ObjCExistentialMetatypeToObjectInst *RHS) {
//      return true;
//   }

   bool visitProjectBlockStorageInst(ProjectBlockStorageInst *RHS) {
      return true;
   }

   bool visitBridgeObjectToRefInst(BridgeObjectToRefInst *X) {
      return true;
   }

   bool visitValueToBridgeObjectInst(ValueToBridgeObjectInst *i) {
      return true;
   }

   bool visitBridgeObjectToWordInst(BridgeObjectToWordInst *X) {
      return true;
   }

   bool visitRefToBridgeObjectInst(RefToBridgeObjectInst *X) {
      return true;
   }
   bool visitClassifyBridgeObjectInst(ClassifyBridgeObjectInst *X) {
      return true;
   }
   bool visitThinFunctionToPointerInst(ThinFunctionToPointerInst *X) {
      return true;
   }
   bool visitPointerToThinFunctionInst(PointerToThinFunctionInst *X) {
      return true;
   }

   // @todo

//   bool visitObjCProtocolInst(ObjCProtocolInst *RHS) {
//      auto *X = cast<ObjCProtocolInst>(LHS);
//      return X->getProtocol() == RHS->getProtocol();
//   }

   bool visitClassMethodInst(ClassMethodInst *RHS) {
      auto *X = cast<ClassMethodInst>(LHS);
      return X->getMember()  == RHS->getMember() &&
             X->getOperand() == RHS->getOperand() &&
             X->getType()    == RHS->getType();
   }

   bool visitSuperMethodInst(SuperMethodInst *RHS) {
      auto *X = cast<SuperMethodInst>(LHS);
      return X->getMember()  == RHS->getMember() &&
             X->getOperand() == RHS->getOperand() &&
             X->getType()    == RHS->getType();
   }

   bool visitObjCMethodInst(ObjCMethodInst *RHS) {
      auto *X = cast<ObjCMethodInst>(LHS);
      return X->getMember()  == RHS->getMember() &&
             X->getOperand() == RHS->getOperand() &&
             X->getType()    == RHS->getType();
   }

   bool visitObjCSuperMethodInst(ObjCSuperMethodInst *RHS) {
      auto *X = cast<ObjCSuperMethodInst>(LHS);
      return X->getMember()  == RHS->getMember() &&
             X->getOperand() == RHS->getOperand() &&
             X->getType()    == RHS->getType();
   }

   bool visitWitnessMethodInst(const WitnessMethodInst *RHS) {
      auto *X = cast<WitnessMethodInst>(LHS);
      if (X->getMember() != RHS->getMember())
         return false;
      if (X->getLookupType() != RHS->getLookupType())
         return false;
      if (X->getConformance() != RHS->getConformance())
         return false;
      return true;
   }

   bool visitMarkDependenceInst(const MarkDependenceInst *RHS) {
      return true;
   }

   bool visitOpenExistentialRefInst(const OpenExistentialRefInst *RHS) {
      return true;
   }

private:
   const PILInstruction *LHS;
};
} // end anonymous namespace

bool PILInstruction::hasIdenticalState(const PILInstruction *RHS) const {
   PILInstruction *UnconstRHS = const_cast<PILInstruction *>(RHS);
   return InstructionIdentityComparer(this).visit(UnconstRHS);
}

namespace {
class AllOperandsAccessor : public PILInstructionVisitor<AllOperandsAccessor,
   ArrayRef<Operand> > {
public:
#define INST(CLASS, PARENT)                                                    \
  ArrayRef<Operand> visit##CLASS(const CLASS *I) {                             \
    ASSERT_IMPLEMENTS(CLASS, PILInstruction, getAllOperands,                   \
                      ArrayRef<Operand>() const);                              \
    return I->getAllOperands();                                                \
  }
#include "polarphp/pil/lang/PILNodesDef.h"
};

class AllOperandsMutableAccessor
   : public PILInstructionVisitor<AllOperandsMutableAccessor,
      MutableArrayRef<Operand> > {
public:
#define INST(CLASS, PARENT)                                                    \
  MutableArrayRef<Operand> visit##CLASS(CLASS *I) {                            \
    ASSERT_IMPLEMENTS(CLASS, PILInstruction, getAllOperands,                   \
                      MutableArrayRef<Operand>());                             \
    return I->getAllOperands();                                                \
  }
#include "polarphp/pil/lang/PILNodesDef.h"
};

#define IMPLEMENTS_METHOD(DerivedClass, BaseClass, MemberName, ExpectedType)  \
  (!::std::is_same<BaseClass, GET_IMPLEMENTING_CLASS(DerivedClass, MemberName,\
                                                     ExpectedType)>::value)

class TypeDependentOperandsAccessor
   : public PILInstructionVisitor<TypeDependentOperandsAccessor,
      ArrayRef<Operand>> {
public:
#define INST(CLASS, PARENT)                                                    \
  ArrayRef<Operand> visit##CLASS(const CLASS *I) {                             \
    if (!IMPLEMENTS_METHOD(CLASS, PILInstruction, getTypeDependentOperands,    \
                           ArrayRef<Operand>() const))                         \
      return {};                                                               \
    return I->getTypeDependentOperands();                                      \
  }
#include "polarphp/pil/lang/PILNodesDef.h"
};

class TypeDependentOperandsMutableAccessor
   : public PILInstructionVisitor<TypeDependentOperandsMutableAccessor,
      MutableArrayRef<Operand> > {
public:
#define INST(CLASS, PARENT)                                                    \
  MutableArrayRef<Operand> visit##CLASS(CLASS *I) {                            \
    if (!IMPLEMENTS_METHOD(CLASS, PILInstruction, getTypeDependentOperands,    \
                           MutableArrayRef<Operand>()))                        \
      return {};                                                               \
    return I->getTypeDependentOperands();                                      \
  }
#include "polarphp/pil/lang/PILNodesDef.h"
};
} // end anonymous namespace

ArrayRef<Operand> PILInstruction::getAllOperands() const {
   return AllOperandsAccessor().visit(const_cast<PILInstruction *>(this));
}

MutableArrayRef<Operand> PILInstruction::getAllOperands() {
   return AllOperandsMutableAccessor().visit(this);
}

ArrayRef<Operand> PILInstruction::getTypeDependentOperands() const {
   return TypeDependentOperandsAccessor().visit(
      const_cast<PILInstruction *>(this));
}

MutableArrayRef<Operand> PILInstruction::getTypeDependentOperands() {
   return TypeDependentOperandsMutableAccessor().visit(this);
}

/// getOperandNumber - Return which operand this is in the operand list of the
/// using instruction.
unsigned Operand::getOperandNumber() const {
   return this - &cast<PILInstruction>(getUser())->getAllOperands()[0];
}

PILInstruction::MemoryBehavior PILInstruction::getMemoryBehavior() const {

   if (auto *BI = dyn_cast<BuiltinInst>(this)) {
      // Handle Swift builtin functions.
      const BuiltinInfo &BInfo = BI->getBuiltinInfo();
      if (BInfo.ID != BuiltinValueKind::None)
         return BInfo.isReadNone() ? MemoryBehavior::None
                                   : MemoryBehavior::MayHaveSideEffects;

      // Handle LLVM intrinsic functions.
      const IntrinsicInfo &IInfo = BI->getIntrinsicInfo();
      if (IInfo.ID != llvm::Intrinsic::not_intrinsic) {
         // Read-only.
         if (IInfo.hasAttribute(llvm::Attribute::ReadOnly) &&
             IInfo.hasAttribute(llvm::Attribute::NoUnwind))
            return MemoryBehavior::MayRead;
         // Read-none?
         return IInfo.hasAttribute(llvm::Attribute::ReadNone) &&
                IInfo.hasAttribute(llvm::Attribute::NoUnwind)
                ? MemoryBehavior::None
                : MemoryBehavior::MayHaveSideEffects;
      }
   }

   // Handle full apply sites that have a resolvable callee function with an
   // effects attribute.
   if (isa<FullApplySite>(this)) {
      FullApplySite Site(const_cast<PILInstruction *>(this));
      if (auto *F = Site.getCalleeFunction()) {
         return F->getEffectsKind() == EffectsKind::ReadNone
                ? MemoryBehavior::None
                : MemoryBehavior::MayHaveSideEffects;
      }
   }

   switch (getKind()) {
#define FULL_INST(CLASS, TEXTUALNAME, PARENT, MEMBEHAVIOR, RELEASINGBEHAVIOR)  \
  case PILInstructionKind::CLASS:                                              \
    return MemoryBehavior::MEMBEHAVIOR;
#include "polarphp/pil/lang/PILNodesDef.h"
   }
   llvm_unreachable("We've just exhausted the switch.");
}

PILInstruction::ReleasingBehavior PILInstruction::getReleasingBehavior() const {
   switch (getKind()) {
#define FULL_INST(CLASS, TEXTUALNAME, PARENT, MEMBEHAVIOR, RELEASINGBEHAVIOR)  \
  case PILInstructionKind::CLASS:                                              \
    return ReleasingBehavior::RELEASINGBEHAVIOR;
#include "polarphp/pil/lang/PILNodesDef.h"
   }
   llvm_unreachable("We've just exhausted the switch.");
}

bool PILInstruction::mayHaveSideEffects() const {
   // If this instruction traps then it must have side effects.
   if (mayTrap())
      return true;

   MemoryBehavior B = getMemoryBehavior();
   return B == MemoryBehavior::MayWrite ||
          B == MemoryBehavior::MayReadWrite ||
          B == MemoryBehavior::MayHaveSideEffects;
}

bool PILInstruction::mayRelease() const {
   if (getReleasingBehavior() ==
       PILInstruction::ReleasingBehavior::DoesNotRelease)
      return false;

   switch (getKind()) {
      default:
         llvm_unreachable("Unhandled releasing instruction!");

      case PILInstructionKind::ApplyInst:
      case PILInstructionKind::TryApplyInst:
      case PILInstructionKind::BeginApplyInst:
      case PILInstructionKind::AbortApplyInst:
      case PILInstructionKind::EndApplyInst:
      case PILInstructionKind::YieldInst:
      case PILInstructionKind::DestroyAddrInst:
      case PILInstructionKind::StrongReleaseInst:
#define ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \
  case PILInstructionKind::Name##ReleaseInst:
#include "polarphp/ast/ReferenceStorageDef.h"
      case PILInstructionKind::ReleaseValueInst:
      case PILInstructionKind::ReleaseValueAddrInst:
         return true;

      case PILInstructionKind::DestroyValueInst:
         assert(!PILModuleConventions(getModule()).useLoweredAddresses());
         return true;

      case PILInstructionKind::UnconditionalCheckedCastAddrInst:
      case PILInstructionKind::UnconditionalCheckedCastValueInst:
         return true;

      case PILInstructionKind::CheckedCastAddrBranchInst: {
         // Failing casts with take_always can release.
         auto *Cast = cast<CheckedCastAddrBranchInst>(this);
         return Cast->getConsumptionKind() == CastConsumptionKind::TakeAlways;
      }

      case PILInstructionKind::CopyAddrInst: {
         auto *CopyAddr = cast<CopyAddrInst>(this);
         // copy_addr without initialization can cause a release.
         return CopyAddr->isInitializationOfDest() ==
                IsInitialization_t::IsNotInitialization;
      }

      case PILInstructionKind::BuiltinInst: {
         auto *BI = cast<BuiltinInst>(this);
         // Builtins without side effects also do not release.
         if (!BI->mayHaveSideEffects())
            return false;
         // If this is a builtin which might have side effect, but its side
         // effects do not cause reference counts to be decremented, return false.
         if (auto Kind = BI->getBuiltinKind()) {
            switch (Kind.getValue()) {
               case BuiltinValueKind::CopyArray:
                  return false;
               default:
                  break;
            }
         }
         if (auto ID = BI->getIntrinsicID()) {
            switch (ID.getValue()) {
               case llvm::Intrinsic::memcpy:
               case llvm::Intrinsic::memmove:
               case llvm::Intrinsic::memset:
                  return false;
               default:
                  break;
            }
         }
         return true;
      }
   }
}

bool PILInstruction::mayReleaseOrReadRefCount() const {
   switch (getKind()) {
      case PILInstructionKind::IsUniqueInst:
      case PILInstructionKind::IsEscapingClosureInst:
         return true;
      default:
         return mayRelease();
   }
}

namespace {
class TrivialCloner : public PILCloner<TrivialCloner> {
   friend class PILCloner<TrivialCloner>;
   friend class PILInstructionVisitor<TrivialCloner>;
   PILInstruction *Result = nullptr;
   TrivialCloner(PILFunction *F) : PILCloner(*F) {}
public:

   static PILInstruction *doIt(PILInstruction *I) {
      TrivialCloner TC(I->getFunction());
      TC.visit(I);
      return TC.Result;
   }

   void postProcess(PILInstruction *Orig, PILInstruction *Cloned) {
      assert(Orig->getFunction() == &getBuilder().getFunction() &&
             "cloning between functions is not supported");

      Result = Cloned;
      PILCloner<TrivialCloner>::postProcess(Orig, Cloned);
   }
   PILValue getMappedValue(PILValue Value) {
      return Value;
   }
   PILBasicBlock *remapBasicBlock(PILBasicBlock *BB) { return BB; }
};
} // end anonymous namespace

bool PILInstruction::isAllocatingStack() const {
   if (isa<AllocStackInst>(this))
      return true;

   if (auto *ARI = dyn_cast<AllocRefInst>(this)) {
      if (ARI->canAllocOnStack())
         return true;
   }

   if (auto *PA = dyn_cast<PartialApplyInst>(this))
      return PA->isOnStack();

   return false;
}

bool PILInstruction::isDeallocatingStack() const {
   if (isa<DeallocStackInst>(this))
      return true;

   if (auto *DRI = dyn_cast<DeallocRefInst>(this)) {
      if (DRI->canAllocOnStack())
         return true;
   }
   return false;
}


/// Create a new copy of this instruction, which retains all of the operands
/// and other information of this one.  If an insertion point is specified,
/// then the new instruction is inserted before the specified point, otherwise
/// the new instruction is returned without a parent.
PILInstruction *PILInstruction::clone(PILInstruction *InsertPt) {
   PILInstruction *NewInst = TrivialCloner::doIt(this);

   if (NewInst && InsertPt)
      InsertPt->getParent()->insert(InsertPt, NewInst);
   return NewInst;
}

/// Returns true if the instruction can be duplicated without any special
/// additional handling. It is important to know this information when
/// you perform such optimizations like e.g. jump-threading.
bool PILInstruction::isTriviallyDuplicatable() const {
   if (isAllocatingStack())
      return false;

   if (auto *ARI = dyn_cast<AllocRefInst>(this)) {
      if (ARI->canAllocOnStack())
         return false;
   }
   if (isa<OpenExistentialAddrInst>(this) || isa<OpenExistentialRefInst>(this) ||
       isa<OpenExistentialMetatypeInst>(this) ||
       isa<OpenExistentialValueInst>(this) || isa<OpenExistentialBoxInst>(this) ||
       isa<OpenExistentialBoxValueInst>(this)) {
      // Don't know how to duplicate these properly yet. Inst.clone() per
      // instruction does not work. Because the follow-up instructions need to
      // reuse the same archetype uuid which would only work if we used a
      // cloner.
      return false;
   }

   if (auto *MI = dyn_cast<MethodInst>(this)) {
      // We can't build SSA for method values that lower to objc methods.
      if (MI->getMember().isForeign)
         return false;
   }
   if (isa<ThrowInst>(this))
      return false;

   // BeginAccess defines the access scope entry point. All associated EndAccess
   // instructions must directly operate on the BeginAccess.
   if (isa<BeginAccessInst>(this))
      return false;

   // begin_apply creates a token that has to be directly used by the
   // corresponding end_apply and abort_apply.
   if (isa<BeginApplyInst>(this))
      return false;

   // dynamic_method_br is not duplicatable because IRGen does not support phi
   // nodes of objc_method type.
   if (isa<DynamicMethodBranchInst>(this))
      return false;

   // If you add more cases here, you should also update PILLoop:canDuplicate.

   return true;
}

bool PILInstruction::mayTrap() const {
   switch(getKind()) {
      case PILInstructionKind::CondFailInst:
      case PILInstructionKind::UnconditionalCheckedCastInst:
      case PILInstructionKind::UnconditionalCheckedCastAddrInst:
         return true;
      default:
         return false;
   }
}

bool PILInstruction::isMetaInstruction() const {
   // Every instruction that implements getVarInfo() should be in this list.
   switch (getKind()) {
      case PILInstructionKind::AllocBoxInst:
      case PILInstructionKind::AllocStackInst:
      case PILInstructionKind::DebugValueInst:
      case PILInstructionKind::DebugValueAddrInst:
         return true;
      default:
         return false;
   }
   llvm_unreachable("Instruction not handled in isMetaInstruction()!");
}

//===----------------------------------------------------------------------===//
//                                 Utilities
//===----------------------------------------------------------------------===//

llvm::raw_ostream &polar::operator<<(llvm::raw_ostream &OS,
                                     PILInstruction::MemoryBehavior B) {
   switch (B) {
      case PILInstruction::MemoryBehavior::None:
         return OS << "None";
      case PILInstruction::MemoryBehavior::MayRead:
         return OS << "MayRead";
      case PILInstruction::MemoryBehavior::MayWrite:
         return OS << "MayWrite";
      case PILInstruction::MemoryBehavior::MayReadWrite:
         return OS << "MayReadWrite";
      case PILInstruction::MemoryBehavior::MayHaveSideEffects:
         return OS << "MayHaveSideEffects";
   }

   llvm_unreachable("Unhandled MemoryBehavior in switch.");
}

llvm::raw_ostream &polar::operator<<(llvm::raw_ostream &OS,
                                     PILInstruction::ReleasingBehavior B) {
   switch (B) {
      case PILInstruction::ReleasingBehavior::DoesNotRelease:
         return OS << "DoesNotRelease";
      case PILInstruction::ReleasingBehavior::MayRelease:
         return OS << "MayRelease";
   }

   llvm_unreachable("Unhandled ReleasingBehavior in switch.");
}

//===----------------------------------------------------------------------===//
//                         PILInstructionResultArray
//===----------------------------------------------------------------------===//

PILInstructionResultArray::PILInstructionResultArray(
   const SingleValueInstruction *SVI)
   : Pointer(), Size(1) {
   // Make sure that even though we are munging things, we are able to get back
   // the original value, types, and operands.
   PILValue originalValue(SVI);
   PILType originalType = SVI->getType();
   (void)originalValue;
   (void)originalType;

   // *PLEASE READ BEFORE CHANGING*
   //
   // Since SingleValueInstruction is both a ValueBase and a PILInstruction, but
   // PILInstruction is the first parent, we need to ensure that our ValueBase *
   // pointer is properly offset. by first static casting to ValueBase and then
   // going back to a uint8_t *.
   auto *Value = static_cast<const ValueBase *>(SVI);
   assert(uintptr_t(Value) != uintptr_t(SVI) &&
             "Expected value to be offset from SVI since it is not the first "
             "multi-inheritence parent");
   Pointer = reinterpret_cast<const uint8_t *>(Value);

#ifndef NDEBUG
   assert(originalValue == (*this)[0] &&
          "Wrong value returned for single result");
   assert(originalType == (*this)[0]->getType());

   auto ValueRange = getValues();
   assert(1 == std::distance(ValueRange.begin(), ValueRange.end()));
   assert(originalValue == *ValueRange.begin());

   auto TypedRange = getTypes();
   assert(1 == std::distance(TypedRange.begin(), TypedRange.end()));
   assert(originalType == *TypedRange.begin());

   PILInstructionResultArray Copy = *this;
   assert(Copy.hasSameTypes(*this));
   assert(Copy == *this);
#endif
}

PILInstructionResultArray::PILInstructionResultArray(
   ArrayRef<MultipleValueInstructionResult> MVResults)
   : Pointer(nullptr), Size(MVResults.size()) {
   // We are assuming here that MultipleValueInstructionResult when static_cast
   // is not offset.
   if (Size)
      Pointer = reinterpret_cast<const uint8_t *>(&MVResults[0]);

#ifndef NDEBUG
   // Verify our invariants.
   assert(size() == MVResults.size());
   auto ValueRange = getValues();
   auto VRangeBegin = ValueRange.begin();
   auto VRangeIter = VRangeBegin;
   auto VRangeEnd = ValueRange.end();
   assert(MVResults.size() == unsigned(std::distance(VRangeBegin, VRangeEnd)));

   auto TypedRange = getTypes();
   auto TRangeBegin = TypedRange.begin();
   auto TRangeIter = TRangeBegin;
   auto TRangeEnd = TypedRange.end();
   assert(MVResults.size() == unsigned(std::distance(TRangeBegin, TRangeEnd)));
   for (unsigned i : indices(MVResults)) {
      assert(PILValue(&MVResults[i]) == (*this)[i]);
      assert(PILValue(&MVResults[i])->getType() == (*this)[i]->getType());
      assert(PILValue(&MVResults[i]) == (*VRangeIter));
      assert(PILValue(&MVResults[i])->getType() == (*VRangeIter)->getType());
      assert(PILValue(&MVResults[i])->getType() == *TRangeIter);
      ++VRangeIter;
      ++TRangeIter;
   }

   PILInstructionResultArray Copy = *this;
   assert(Copy.hasSameTypes(*this));
   assert(Copy == *this);
#endif
}

PILValue PILInstructionResultArray::operator[](size_t Index) const {
   assert(Index < Size && "Index out of bounds");
   // *NOTE* In the case where we have a single instruction, Index will always
   // necessarily be 0 implying that it is safe for us to just multiple Index by
   // sizeof(MultipleValueInstructionResult).
   size_t Offset = sizeof(MultipleValueInstructionResult) * Index;
   return PILValue(reinterpret_cast<const ValueBase *>(&Pointer[Offset]));
}

bool PILInstructionResultArray::hasSameTypes(
   const PILInstructionResultArray &rhs) {
   auto &lhs = *this;
   if (lhs.size() != rhs.size())
      return false;
   for (unsigned i : indices(lhs)) {
      if (lhs[i]->getType() != rhs[i]->getType())
         return false;
   }
   return true;
}

bool PILInstructionResultArray::
operator==(const PILInstructionResultArray &other) {
   if (size() != other.size())
      return false;
   for (auto i : indices(*this))
      if ((*this)[i] != other[i])
         return false;
   return true;
}

PILInstructionResultArray::type_range
PILInstructionResultArray::getTypes() const {
   PILType (*F)(PILValue) = [](PILValue V) -> PILType {
      return V->getType();
   };
   return {llvm::map_iterator(begin(), F), llvm::map_iterator(end(), F)};
}

const ValueBase *PILInstructionResultArray::front() const {
   assert(size() && "Can not access front of an empty result array");
   return *begin();
}

const ValueBase *PILInstructionResultArray::back() const {
   assert(size() && "Can not access back of an empty result array");
   if (std::next(begin()) == end()) {
      return *begin();
   }
   return *std::prev(end());
}

//===----------------------------------------------------------------------===//
//                         Multiple Value Instruction
//===----------------------------------------------------------------------===//

Optional<unsigned>
MultipleValueInstruction::getIndexOfResult(PILValue Target) const {
   // First make sure we actually have one of our instruction results.
   auto *MVIR = dyn_cast<MultipleValueInstructionResult>(Target);
   if (!MVIR || MVIR->getParent() != this)
      return None;
   return MVIR->getIndex();
}

MultipleValueInstructionResult::MultipleValueInstructionResult(
   ValueKind valueKind, unsigned index, PILType type,
   ValueOwnershipKind ownershipKind)
   : ValueBase(valueKind, type, IsRepresentative::No) {
   setOwnershipKind(ownershipKind);
   setIndex(index);
}

void MultipleValueInstructionResult::setOwnershipKind(
   ValueOwnershipKind NewKind) {
   Bits.MultipleValueInstructionResult.VOKind = unsigned(NewKind);
}

void MultipleValueInstructionResult::setIndex(unsigned NewIndex) {
   // We currently use 32 bits to store the Index. A previous comment wrote
   // that "500k fields is probably enough".
   Bits.MultipleValueInstructionResult.Index = NewIndex;
}

ValueOwnershipKind MultipleValueInstructionResult::getOwnershipKind() const {
   return ValueOwnershipKind(Bits.MultipleValueInstructionResult.VOKind);
}

MultipleValueInstruction *MultipleValueInstructionResult::getParent() {
   char *Ptr = reinterpret_cast<char *>(
      const_cast<MultipleValueInstructionResult *>(this));

   // We know that we are in a trailing objects array with an extra prefix
   // element that contains the pointer to our parent PILNode. So grab the
   // address of the beginning of the array.
   Ptr -= getIndex() * sizeof(MultipleValueInstructionResult);

   // We may have some bytes of padding depending on our platform. Move past
   // those bytes if we need to.
   static_assert(alignof(MultipleValueInstructionResult) >=
                 alignof(MultipleValueInstruction *),
                 "We assume this relationship in between the alignments");
   Ptr -= alignof(MultipleValueInstructionResult) -
          alignof(MultipleValueInstruction *);

   // Then subtract the size of MultipleValueInstruction.
   Ptr -= sizeof(MultipleValueInstruction *);

   // Now that we have the correct address of our parent instruction, grab it and
   // return it avoiding type punning.
   uintptr_t value;
   memcpy(&value, Ptr, sizeof(value));
   return reinterpret_cast<MultipleValueInstruction *>(value);
}

#ifndef NDEBUG

//---
// Static verification of multiple value properties.
//

// Make sure that all subclasses of MultipleValueInstruction implement
// getAllResults()
#define MULTIPLE_VALUE_INST(ID, TEXTUALNAME, PARENT, MEMBEHAVIOR, MAYRELEASE)  \
  static_assert(IMPLEMENTS_METHOD(ID, PARENT, getAllResults,                   \
                                  PILInstructionResultArray() const),          \
                #ID " does not implement PILInstructionResultArray "           \
                    "getAllResults() const?!");

// Check that all subclasses of MultipleValueInstructionResult are the same size
// as MultipleValueInstructionResult.
//
// If this changes, we just need to expand the size fo PILInstructionResultArray
// to contain a stride. But we assume this now so we should enforce it.
#define MULTIPLE_VALUE_INST_RESULT(ID, PARENT)                                 \
  static_assert(                                                               \
      sizeof(ID) == sizeof(PARENT) && alignof(ID) == alignof(PARENT),          \
      "Expected all multiple value inst result to be the same size?!");
#include "polarphp/pil/lang/PILNodesDef.h"

#endif
